package mx.com.crowdgine.entity.geometry;

import java.nio.FloatBuffer;
import java.util.LinkedList;
import java.util.List;

import javax.media.opengl.GL4bc;
import javax.media.opengl.glu.GLU;

import mx.com.crowdgine.assetloader.RawTexture;

import com.jogamp.common.nio.Buffers;

import mx.com.crowdgine.entity.Entity;
import mx.com.crowdgine.util.math.Vector3f;

public class Cube implements Entity {
	
	private float size;
	private Vector3f position;
	private int vertexCount;

	private List<Float> vertices;
	private Vector3f color;
	private boolean hasTexture = false;
	
	private FloatBuffer vertexBuffer;
	private FloatBuffer colorBuffer;
	
	public Cube(float size){
		this.size=size;
		position = new Vector3f(0,0,0);
		this.initVertices();
		this.color = new Vector3f(1.0f, 0.0f, 0.0f);
		this.createBuffers();
	}
	
	public Cube(float size, Vector3f position) {
		this.position = position;
		this.size = size;
		this.initVertices();
		this.color = new Vector3f(1.0f, 0.0f, 0.0f);
		this.createBuffers();
	}
	
	public Cube(float width, float height, float depth, Vector3f position){
		this.position = position;
		this.initVertices(width, height, depth);
		this.color = new Vector3f(1.0f, 0.0f, 0.0f);
		this.createBuffers();
	}
	
	public Cube(float width, float height, float depth, Vector3f position, Vector3f color){
		this.position = position;
		this.initVertices(width, height, depth);
		this.color = color;
		this.createBuffers();
	}
	
	private void initVertices(float width, float height, float depth){
		this.vertices = new LinkedList<Float>();
		float widthOffset = width/2;
		float heightOffset = height/2;
		float depthOffset = depth/2;
		
		// front face bottom triangle
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		// front face top triangle
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		// right face bottom triangle
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		// right face top triangle
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		// back face bottom triangle
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		
		// back face top triangle
		this.vertices.add(position.getX()+widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);;
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		// left face bottom triangle
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		// left face top triangle
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()+depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()+heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
		
		this.vertices.add(position.getX()-widthOffset);
		this.vertices.add(position.getY()-heightOffset);
		this.vertices.add(position.getZ()-depthOffset);
	}
	
	private void initVertices() {
		this.vertices = new LinkedList<Float>();
		float offset = size/2;
		// front face bottom triangle
		this.vertices.add(position.getX()-offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()-offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()-offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()-offset);
		
		// front face top triangle
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()-offset);
		
		this.vertices.add(position.getX()-offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()-offset);
		
		this.vertices.add(position.getX()-offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()-offset);
		
		// right face bottom triangle
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()-offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()+offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()+offset);
		
		// right face top triangle
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()+offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()-offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()-offset);
		
		// back face bottom triangle
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()+offset);
		
		this.vertices.add(position.getX()-offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()+offset);
		
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()+offset);
		
		
		// back face top triangle
		this.vertices.add(position.getX()+offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()+offset);
		
		this.vertices.add(position.getX()-offset);
		this.vertices.add(position.getY()+offset);
		this.vertices.add(position.getZ()+offset);;
		
		this.vertices.add(position.getX()-offset);
		this.vertices.add(position.getY()-offset);
		this.vertices.add(position.getZ()+offset);
		
		/*
		// front face bottom triangle
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        
        // front face top triangle
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        
        this.vertices.add(0.0f);
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        
        // right face bottom triangle
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        this.vertices.add(-this.size);
        
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(-this.size);
        
        // right face top triangle
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(-this.size);
        
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        
        // back face bottom triangle
        this.vertices.add(this.size);
        this.vertices.add(0.0f);
        this.vertices.add(-this.size);
        
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        this.vertices.add(-this.size);
        
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(-this.size);
        
        
        // back face top triangle
        this.vertices.add(0.0f);
        this.vertices.add(0.0f);
        this.vertices.add(-this.size);
        
        this.vertices.add(0.0f);
        this.vertices.add(this.size);
        this.vertices.add(-this.size);
        
        this.vertices.add(this.size);
        this.vertices.add(this.size);
        this.vertices.add(-this.size);
        */

	}
	
	public float getSize() {
		return size;
	}

	public void setSize(float size) {
		throw new UnsupportedOperationException();
	}
	
	public boolean bindTexture(int target){
		if(this.hasTexture){
			//Bind OGL texture
		}
		return false;
	}
	
	public boolean unbindTexture(int target){
		//Unbind OGL texture
		return true;
	}
	
	@Override
	public void translate(Vector3f trans){
		float transX = trans.getX();
		float transY = trans.getY();
		float transZ = trans.getZ();
		for (int i=0;i<vertices.size();i++){
			if(i % 3 == 0){
				vertices.set(i, vertices.get(i)+transX);
			}else if(i % 3 == 1){
				vertices.set(i, vertices.get(i)+transY);
			}else{
				vertices.set(i, vertices.get(i)+transZ);
			}
		}
		position.set(position.getX()+transX, position.getY()+transY, position.getZ()+transZ);
	}
	
	@Override
	public boolean hasTexture(){
		return hasTexture;
	}
	
	private void createBuffers(){
		float [] vertexPrimitives = new float[this.vertices.size()];
		
		int i = 0;
		for(Float vertex : this.vertices) {
			vertexPrimitives[i] = vertex;
			i++;
		}
		vertexBuffer = Buffers.newDirectFloatBuffer(vertexPrimitives);
		
		vertexCount = vertexPrimitives.length/3;
		
		float [] vertexColors = new float[this.vertices.size()];
		for(i = 0; i <= vertexColors.length - 3; i+=3) {
			vertexColors[i + 0] = color.getX();
			vertexColors[i + 1] = color.getY();
			vertexColors[i + 2] = color.getZ();
		}
		
		colorBuffer = Buffers.newDirectFloatBuffer(vertexColors);
	}
	
	@Override
	public FloatBuffer getVertices() {
		return vertexBuffer;
	}
	
	@Override
	public FloatBuffer getVertexColors() {
		return colorBuffer;
	}

	@Override
	public Vector3f getPosition() {
		return position;
	}

	@Override
	public int getVertexCount() {
		return vertexCount;
	}

	@Override
	public boolean initRawTexture(RawTexture rawTexture, GL4bc gl, GLU glu) {
		throw new UnsupportedOperationException("initRawTexture in Cube not implemented");
	}
}
